package com.sheng.leetcode.year2023.month03.day07;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

/**
 * @author liusheng
 * @date 2023/03/07
 * <p>
 * 1096. 花括号展开 II<p>
 * <p>
 * 如果你熟悉 Shell 编程，那么一定了解过花括号展开，它可以用来生成任意字符串。<p>
 * 花括号展开的表达式可以看作一个由 花括号、逗号 和 小写英文字母 组成的字符串，定义下面几条语法规则：<p>
 * 如果只给出单一的元素 x，那么表达式表示的字符串就只有 "x"。R(x) = {x}<p>
 * 例如，表达式 "a" 表示字符串 "a"。<p>
 * 而表达式 "w" 就表示字符串 "w"。<p>
 * 当两个或多个表达式并列，以逗号分隔，我们取这些表达式中元素的并集。R({e_1,e_2,...}) = R(e_1) ∪ R(e_2) ∪ ...<p>
 * 例如，表达式 "{a,b,c}" 表示字符串 "a","b","c"。<p>
 * 而表达式 "{{a,b},{b,c}}" 也可以表示字符串 "a","b","c"。<p>
 * 要是两个或多个表达式相接，中间没有隔开时，我们从这些表达式中各取一个元素依次连接形成字符串。<p>
 * R(e_1 + e_2) = {a + b for (a, b) in R(e_1) × R(e_2)}<p>
 * 例如，表达式 "{a,b}{c,d}" 表示字符串 "ac","ad","bc","bd"。<p>
 * 表达式之间允许嵌套，单一元素与表达式的连接也是允许的。<p>
 * 例如，表达式 "a{b,c,d}" 表示字符串 "ab","ac","ad" 。<p>
 * 例如，表达式 "a{b,c}{d,e}f{g,h}" 可以表示字符串 "abdfg", "abdfh", "abefg", "abefh", "acdfg", "acdfh", "acefg", "acefh"。<p>
 * 给出表示基于给定语法规则的表达式 expression，返回它所表示的所有字符串组成的有序列表。<p>
 * 假如你希望以「集合」的概念了解此题，也可以通过点击 “显示英文描述” 获取详情。<p>
 * <p>
 * 示例 1：<p>
 * 输入：expression = "{a,b}{c,{d,e}}"<p>
 * 输出：["ac","ad","ae","bc","bd","be"]<p>
 * <p>
 * 示例 2：<p>
 * 输入：expression = "{{a,z},a{b,c},{ab,z}}"<p>
 * 输出：["a","ab","ac","z"]<p>
 * 解释：输出中 不应 出现重复的组合结果。<p>
 * <p>
 * 提示：<p>
 * 1 <= expression.length <= 60<p>
 * expression[i] 由 '{'，'}'，',' 或小写英文字母组成<p>
 * 给出的表达式 expression 用以表示一组基于题目描述中语法构造的字符串<p>
 * <p>
 * 来源：力扣（LeetCode）<p>
 * 链接：<a href="https://leetcode.cn/problems/brace-expansion-ii">1096. 花括号展开 II</a><p>
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。<p>
 */
public class LeetCode1096 {

    @Test
    public void test01() {
        String expression = "{a,b}{c,{d,e}}";
//        String expression = "{{a,z},a{b,c},{ab,z}}";
        System.out.println(new Solution().braceExpansionII(expression));
    }
}

class Solution {

    TreeSet<String> treeSet = new TreeSet<>();

    public List<String> braceExpansionII(String expression) {
        // "{a,b,c}" 表示字符串 "a","b","c"
        // "{{a,b},{b,c}}" 也可以表示字符串 "a","b","c"
        // "{a,b}{c,d}" 表示字符串 "ac","ad","bc","bd"
        // "a{b,c,d}" 表示字符串 "ab","ac","ad"
        // "a{b,c}{d,e}f{g,h}" 可以表示字符串 "abdfg", "abdfh", "abefg", "abefh", "acdfg", "acdfh", "acefg", "acefh"
        // 解读，如果在 } 和 { 之间有逗号进行分割，代表左右两边是加法组合，否则为乘法组合
        dfs(expression);
        return new ArrayList<>(treeSet);
    }

    private void dfs(String exp) {
        int j = exp.indexOf('}');
        if (j == -1) {
            treeSet.add(exp);
            return;
        }
        int i = j;
        while (exp.charAt(i) != '{') {
            --i;
        }
        String a = exp.substring(0, i);
        String c = exp.substring(j + 1);
        for (String b : exp.substring(i + 1, j).split(",")) {
            dfs(a + b + c);
        }
    }
}
